﻿using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using System.Web.Caching;
using System.Timers;
using Liber;
using Liber.WEB;

namespace SoBusiness.Controllers
{
    /// <summary>
    /// 为外部应用提供统一的开放接口服务
    /// </summary>
    public class OpenTLController : LiberController
    {
        [NoSession]
        public void OnOpenMessage(string appId, string appToken,string sec="", string sync="")
        {
            var tk=HttpContext.Cache.Get(appId);
            if (tk != null&&tk.ToString()==appToken) //检查token是否有效
            {
                
                if (sync !="") //是否仅仅是同步状态信息
                {            
                   var getInfo= API.NoauthorRequest("OpenAppSvc@GetAppInfo")
                                   .Set("appid", appId)
                                   .WaitResult();
                   XMLSetting rtn = XMLSetting.LoadFromStr(@"<xml>
                                                             <IsPositive>true</IsPositive>
                                                             </xml>");
                   if (getInfo.IsPositive)
                   {
                       rtn.First("IsPositive").Value = "true";
                       rtn.First("LastSync").Value = getInfo.Data["lastsync"].ToString();
                       HttpContext.Response.Write(rtn.InnerXML);
                       HttpContext.Response.End();
                       rtn.Dispose();
                   }
                   else
                   {
                       rtn.First("IsPositive").Value = "false";
                       HttpContext.Response.Write(rtn.InnerXML);
                       HttpContext.Response.End();
                       rtn.Dispose();
                   }
                }
                else
                {
                    
                    XMLSetting data = null;
                    //否则执行特定Action
                    if (!string.IsNullOrEmpty(sec)) {
                        //TODO:根据appId查找注册时设置的appSec
                        var app = API.NoauthorRequest("OpenAppSvc@GetAppInfo")
                                   .Set("appid", appId)
                                   .WaitResult();
                        
                        byte[] indata = new byte[HttpContext.Request.InputStream.Length];
                        HttpContext.Request.InputStream.Read(indata, 0, indata.Length);
                        string inText=indata.AESDecrypt(app.Data["appsec"].ToString());
                        data = XMLSetting.LoadFromStr(inText);
                    }
                    else
                    {   var rsp = new XmlDocument();
                        rsp.Load(HttpContext.Request.InputStream);
                        data = XMLSetting.LoadFromStr(rsp.InnerXml);
                    }

                    HttpContext.Response.Write("");
                    HttpContext.Response.End();
                    var api = data.First("API").All(); 

                    API.NoauthorRequest("OpenAppSvc@UpdateApp")
                                   .Set("lastsync", data.First("LastSync").Value)
                                   .Set("appid", data.First("AppID").Value)
                                   .WaitResult();
                    foreach(var a in api)
                    {
                        if (a.First("Count").Value != "0")
                        {
                            API.Post(-1, a.Name.Replace("_","@"))
                               .Set("appid", data.First("AppID").Value)
                               .Set("opendata", "<xml>" + a.First("Items").Value + "</xml>")
                               .End();
                            break;
                        }
                    }
                }
            }
            else
            {
                HttpContext.Response.Write("");
                HttpContext.Response.End();
            }
        }

        [NoSession]
        /// <summary>
        /// 开放应用主动访问平台时用于验证其身份
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appTicket"></param>
        public void GetToken(string appId, string appTicket)
        {
            XMLSetting rtn = XMLSetting.LoadFromStr(@"<xml>
                                                      <IsPositive>true</IsPositive>
                                                      </xml>");

            var app = API.NoauthorRequest("OpenAppSvc@GetAppInfo")
                       .Set("appid", appId)
                       .WaitResult();
            if (app.IsPositive)
            {
                string appSec = app.Data["appsec"].ToString();
                if ((appId + appSec).MD5Encrypt() == appTicket)
                {
                    string tkn = ( appId + appSec+DateTime.Now.ToString()).MD5Encrypt();
                    rtn.First("IsPositive").Value = "true";
                    rtn.First("TokenExpire").Value = "1000";
                    rtn.First("AppToken").Value = tkn;
                    HttpContext.Cache.Add(appId, tkn, null, DateTime.Now.AddMinutes(1001), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
                }
                else
                {
                    rtn.First("IsPositive").Value = "false";

                }
            }
            else
            {
                rtn.First("IsPositive").Value = "false";
            }

            HttpContext.Response.Write(rtn.InnerXML);
            HttpContext.Response.End();
            rtn.Dispose();
        }

        [NoSession]
        /// <summary>
        /// 拉取当前用户所属公司下注册的开放应用所的提供的业务数据
        /// </summary>
        /// <returns></returns>
        public JsonResult SyncFromOpenApp(long appid=-1)
        {
            FnResult<DyObject> rsult = FnResult<DyObject>.Sucess(new DyObject());

            //获取所有或指定的第三方应用程序下已应用的pull或sync模式的API
            var apis = API.NoauthorRequest("OpenAppSvc@GetSyncApi")
                          .Set("appid",appid)
                          .WaitResult();
            if (!apis.IsPositive || apis.Data["OpenAPIs"] == null)
            {
                return Json(FnResult<DyObject>.Failure("OpenTL", "NoOpenAPI"));
            }

            List<DyObject> oapis = (List<DyObject>)apis.Data["OpenAPIs"];

            foreach (var api in oapis)
            {
                DyObject queryStr = new DyObject();
                DateTime ts = DateTime.Now;
                //调用每个api立刻拉取或同步数据
                queryStr.Set("signature", Server.UrlEncode((api["appid"].ToString() + api["apptoken"].ToString() + ts.ToString()).Encode()))
                        .Set("timespan", ts.ToString())
                        .Set("lastsynctime", api["syncend"].ToString())
                        .Set("msgType", api["name"].ToString());

                var rp = WebHelper.GetResponseFrom(api["url"].ToString(), queryStr);
                queryStr.Dispose();
                if (rp != null)
                {
                    //立刻将数据传递到后台进行处理
                    try
                    {
                        XMLSetting data = null;
                        if (string.IsNullOrWhiteSpace(api["sec"].ToString()))
                        {
                            var rsp = new XmlDocument();
                            rsp.LoadXml(rp.ReadToStr());
                            data = XMLSetting.LoadFromStr(rsp.InnerXml);
                        }
                        else
                        {
                            string inText = rp.ReadToStr().AESDecrypt(api["appsec"].ToString());
                            data = XMLSetting.LoadFromStr(inText);
                        }
                
                        rp.Dispose();
                        if (data.First("IsPositive").Value == "false")
                        {
                            //TODO:记录错误，继续处理下一个API
                        }
                        else
                        {
                            if (data.First("Data").First("ItemCount", false) != null && data.First("Data").First("ItemCount").Value != "0")
                            {
                                var up = API.NoauthorRequest("OpenAppSvc@UpdateAPI")
                                            .Set("syncbegin", data.First("SyncBegin").Value)
                                            .Set("syncend", data.First("SyncEnd").Value)
                                            .Set("apiid", long.Parse(api["id"].ToString()))
                                            .WaitResult();
                                if (up.IsPositive)
                                {
                                    API.Post(-1, api["name"].ToString())
                                        .Set("appid", long.Parse(api["appid"].ToString()))
                                        .Set("opendata", "<xml>" + data.First("Data").First("Items").Value + "</xml>")
                                        .WaitResult();
                                    rsult.Data.Set(api["name"].ToString(), "SyncSucess"+ data.First("Data").First("ItemCount").Value);
                                    Log(rsult.Data.FastJson());
                                }                                  
                            }
                            else
                            {
                                rsult.Data.Set(api["name"].ToString(), "NothingNeedSync");
                            }
                        }
                        data.Dispose();
                    }
                    catch (Exception ex)
                    {
                        //TODO:记录错误，继续处理下一个API
                        Log("同步接口调用时捕获到异常："+ex.Message);
                    }
                    finally
                    {
                        rp.Dispose();
                    }
                }
                else
                {
                    rsult = FnResult<DyObject>.Failure("OpenTL", "NoResponseFromOpenAPP");
                }
            }
            return Json(rsult);
        }

        public JsonResult IniHistory(string historyDataType)
        {
            FnResult<DyObject> rsult = FnResult<DyObject>.Sucess(new DyObject());

            //TODO:获取所有注册的第三方应用程序       
            var apps = API.NoauthorRequest("OpenAppSvc@GetOpenApp")
                          .WaitResult();
            if (!apps.IsPositive || apps.Data["OpenAPP"] == null)
            {
                return Json(FnResult<DyObject>.Failure("OpenTL", "NoOpenAPP"));
            }

            List<DyObject> oapps = (List<DyObject>)apps.Data["OpenAPP"];
            DyObject queryStr = new DyObject();
            foreach (var app in oapps)
            {
                DateTime ts = DateTime.Now;
                //通知每个app立刻同步数据
                queryStr.Set("signature", Server.UrlEncode((app["appid"].ToString() + app["apptoken"].ToString() + ts.ToString()).Encode()))
                        .Set("timespan", ts.ToString())
                        .Set("msgType", historyDataType);

                var rp = WebHelper.GetResponseFrom(app["url"].ToString(), queryStr);
                queryStr.Dispose();
                if (rp != null)
                {
                    try
                    {
                        XMLSetting data = null;
                        if (string.IsNullOrWhiteSpace(app["sec"].ToString()))
                        {
                            var rsp = new XmlDocument();
                            rsp.LoadXml(rp.ReadToStr());
                            data = XMLSetting.LoadFromStr(rsp.InnerXml);
                        }
                        else
                        {
                            string inText = rp.ReadToStr().AESDecrypt(app["appsec"].ToString());
                            data = XMLSetting.LoadFromStr(inText);
                        }
                        rp.Dispose();
                        if (data.First("IsPositive").Value == "false")
                        {
                            rsult = FnResult<DyObject>.Failure(app["appid"].ToString(), "IniHistoryError").SetError("Message", data.First("Error").Value);
                            break;
                        }

                        //执行特定的的API
                        var a = data.First("PurchaseApp_"+historyDataType);
                        if (a.First("ItemCount", false) != null && a.First("ItemCount").Value != "0")
                        {
                            API.Post(-1, "PurchaseApp@"+historyDataType)
                                .Set("appid", data.First("AppID").Value)
                                .Set("opendata", "<xml>" + a.First("Items").Value + "</xml>")
                                .End();
                            rsult.Data.Set(a.Name, "SyncSucess");
                        }

                        data.Dispose();
                    }
                    catch (Exception ex)
                    {
                        rsult = FnResult<DyObject>.Failure("OpenTL", "IniHistoryOpenDataFailure").SetError("exception", ex.Message);
                        break;
                    }
                    finally
                    {
                        rp.Dispose();
                    }
                }
                else
                {
                    rsult = FnResult<DyObject>.Failure("OpenTL", "NoResponseFromOpenAPP");
                }
            }
            return Json(rsult);
        }

        public JsonResult IsOpenAppReady(string appid, string apptoken, string url)
        {
            DyObject args = new DyObject();
            DateTime t = DateTime.Now;
            string echo = IdFactory.NewID().ToString() + t.ToString();
            args.Set("signature", (appid + apptoken + t.ToString()).Encode())
                .Set("timespan", t.ToString())
                .Set("msgType", "echo")
                .Set("lastSyncTime", t.ToString())
                .Set("echo", echo);

            var chk = WebHelper.GetResponseFrom(url, args);
            try
            {
                string rtnEcoh = chk.ReadToStr();
                if (rtnEcoh == echo)
                {
                    return Json(FnResult.Sucess(null));
                }
                else
                {
                    return Json(FnResult.Failure("OpenTLController", "OpenAppUnready"));
                }
            }
            catch(Exception ex)
            {
                return Json(FnResult.Failure("OpenTLController", "OpenAppUnready"));
            }
        }
    }

    public class TPL
    {
        public const string Token = @"<xml>
                                    <IsPositive>true</IsPositive>
                                    </xml>";
    }
}